package ba03_Around;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author HLF
 * @version V1.0
 * @package ba01
 * @date 2021/10/17 10:19
 * @Aspect 是aspectj框架的注解，表示当前类是切面类
 * 切面类：用来给业务方法增加功能的类，在这个类中有增加切面功能的代码
 * 位置：在切面类定义的上面
 */
@Aspect
public class MyAspect {
    /**
     * 环绕通知方法的定义格式
     *  1.public
     *  2.必须有一个返回值，推荐使用Object(就是目标方法的返回值)
     *  3.方法名称自定义
     *  4.方法有参数，固定的参数 ProceedingJoinPoint
     */
    /**
     * @Around: 环绕通知
     * 属性：value 切入点表达式
     * 位置：在方法的定义上面
     * 特点：
     * 1.它是功能最强的通知
     * 2.在目标方法的前和后都能增强功能。
     * 3.控制目标方法是否被调用执行
     * 4.修改原来的目标方法的执行结果。 影响最后的调用结果
     * <p>
     * 环绕通知，等同于jdk动态代理的，InvocationHandler接口
     * <p>
     * 参数：  ProceedingJoinPoint 就等同于 Method
     * 作用：执行目标方法的
     * 返回值： 就是目标方法的执行结果，可以被修改。
     * <p>
     * 环绕通知： 经常做事务， 在目标方法之前开启事务，执行目标方法， 在目标方法之后提交事务
     */

    @Around(value = "execution(* ba03_Around.SomeServiceImpl.doFirst(..))")
    public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
        //获取目标方法的第一个参数name
        String name = "";
        Object[] args = pjp.getArgs();
        if (args != null && args.length>1){
            name = (String) args[0];
        }


        //实现环绕通知
        Object res = null;//定义目标方法的返回值

        System.out.println("环绕通知：目标方法执行之前输出日志：" +
                new SimpleDateFormat("yyyy-MM-dd hh:mm:ss SSS").format(new Date()));

        if ("zhangsan".equals(name)){
            //目标方法的调用
            res = pjp.proceed();//相当于method.invoke();  Object res = doFirst();
        }

        System.out.println("环绕通知：目标方法执行之后，增加事务功能");

        if (res != null) {
            res = "Hello AspectJ AOP";
        }

        return res;
    }
}
